package com.haoran.dwz.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.haoran.dwz.domain.entities.ApiLog;
import com.haoran.dwz.repository.ApiLogRepository;


@Service
public class ApiLogService {

	@Autowired
	private ApiLogRepository apiLogRepository;
	
	
	public Page<ApiLog>  findByPageable(Pageable pageable){
		return apiLogRepository.findAll(pageable);
	}
	
	/**
	 * 接口调用次数
	 */
	public long count() {
		return  apiLogRepository.count();
	}
	
	public long count(Date stime) {
		 Specification<ApiLog> querySpecifi = new Specification<ApiLog>() {
	            @Override
	            public Predicate toPredicate(Root<ApiLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
	                List<Predicate> predicates = new ArrayList<>();
	                if (stime != null) {
	                    //大于或等于传入时间
	                    predicates.add(cb.greaterThanOrEqualTo(root.get("requestTime").as(Date.class), stime));
	                }
	                // and到一起的话所有条件就是且关系，or就是或关系
	                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	            }
	        };
        return  apiLogRepository.count(querySpecifi);
	}
	
	  public List<ApiLog> search(String apiName, Date stime, Date etime) {
	        List<ApiLog> resultList = null;
	        Specification<ApiLog> querySpecifi = new Specification<ApiLog>() {
	            @Override
	            public Predicate toPredicate(Root<ApiLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
	                List<Predicate> predicates = new ArrayList<>();
	                if (stime != null) {
	                    //大于或等于传入时间
	                    predicates.add(cb.greaterThanOrEqualTo(root.get("requestTime").as(Date.class), stime));
	                }
	                if (etime != null) {
	                    //小于或等于传入时间
	                    predicates.add(cb.lessThanOrEqualTo(root.get("requestTime").as(Date.class), etime));
	                }
	                if (StringUtils.isNotBlank(apiName)) {
	                    //模糊查找
	                    predicates.add(cb.like(root.get("apiName").as(String.class), "%" + apiName + "%"));
	                }
	                // and到一起的话所有条件就是且关系，or就是或关系
	                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	            }
	        };
	        resultList = apiLogRepository.findAll(querySpecifi);
	        return resultList;
	    }
	  
	  /**
	   * 成功的调用
	   * @param stime
	   * @param etime
	   * @return
	   */
	  public List<ApiLog> search(Date stime, Date etime) {
	        List<ApiLog> resultList = null;
	        Specification<ApiLog> querySpecifi = new Specification<ApiLog>() {
	            @Override
	            public Predicate toPredicate(Root<ApiLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
	                List<Predicate> predicates = new ArrayList<>();
	                if (stime != null) {
	                    //大于或等于传入时间
	                    predicates.add(cb.greaterThanOrEqualTo(root.get("requestTime").as(Date.class), stime));
	                }
	                if (etime != null) {
	                    //小于或等于传入时间
	                    predicates.add(cb.lessThanOrEqualTo(root.get("requestTime").as(Date.class), etime));
	                } 
	                predicates.add(cb.isTrue(root.get("isSuccess")));
	                // and到一起的话所有条件就是且关系，or就是或关系
	                if (predicates.size() > 0) {  
	                	return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	                }
	                return cb.conjunction();
	            }
	        };
	        resultList = apiLogRepository.findAll(querySpecifi);
	        return resultList;
	    }
	
	
	public Map<String,Object> lastMonthStatistics(int lastDays){
		Map<String, Object> result = new HashMap<String, Object>();
		List<String> triggerDayList = new ArrayList<String>();
		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
		DateTime today = new DateTime().withTimeAtStartOfDay();
		for (int i = lastDays; i>= 0; i--) {
			DateTime minusDays = today.minusDays(i);
			Date date = minusDays.toDate();
			List<ApiLog> re1 = search(date,today.minusDays(i-1).toDate());
			List<ApiLog> re2 = search(null,date,today.minusDays(i-1).toDate());
			triggerDayList.add(minusDays.toString("yyyy-MM-dd"));
			triggerDayCountSucList.add(re1.size());
			triggerDayCountFailList.add(re2.size()-re1.size());
		}
		int apiCallCountSucTotal = search(today.minusDays(lastDays).toDate(),null).size();
		long apiCallCountFailTotal = count(today.minusDays(lastDays).toDate())-apiCallCountSucTotal;
		result.put("apiCallDayList", triggerDayList);
		result.put("apiCallDayCountSucList", triggerDayCountSucList);
		result.put("apiCallDayCountFailList", triggerDayCountFailList);
		result.put("apiCallCountSucTotal", apiCallCountSucTotal);
		result.put("apiCallCountFailTotal", apiCallCountFailTotal);
		
		return result;
	}
	
	
	
	/**
	 * 成功率
	 * @return
	 */
	public BigDecimal[] successRate() {
		BigDecimal[] arr = new BigDecimal[2];
		long count = apiLogRepository.count();
		arr[0] = new BigDecimal(count);
		if(count > 0) {
			List<ApiLog> findByIsSuccess = apiLogRepository.findByIsSuccess(true);
			if(!findByIsSuccess.isEmpty()) {
				BigDecimal bigDecimal = new BigDecimal(findByIsSuccess.size());
				arr[1] = bigDecimal.divide(new BigDecimal(count),4,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2);
			}else {
				arr[1]=BigDecimal.ZERO.multiply(new BigDecimal(100)).setScale(2);
			}
		}else {
			arr[1]=BigDecimal.ONE.multiply(new BigDecimal(100)).setScale(2);
		}
		return arr;
	}

	public Page<ApiLog> findByPageable(ApiLog apiLog, Pageable pageable) {
		Specification<ApiLog> querySpecifi = new Specification<ApiLog>() {
			@Override
			public Predicate toPredicate(Root<ApiLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<>();
				
				Date startDateTime = apiLog.getStartDateTime();
				Date endDateTime = apiLog.getEndDateTime();
				if (startDateTime != null && endDateTime != null) {
					// 大于或等于传入时间
					Predicate between = cb.and(cb.greaterThanOrEqualTo(root.get("requestTime").as(Date.class), startDateTime),cb.lessThanOrEqualTo(root.get("requestTime").as(Date.class), endDateTime));
					Predicate time = cb.or(cb.and(cb.isNull(root.get("requestTime").as(Date.class))),between);
					predicates.add(time);
				}
				if (StringUtils.isNotBlank(apiLog.getParams())) {
                    //模糊查找
                    predicates.add(cb.or(cb.like(root.get("params").as(String.class), "%" + apiLog.getParams() + "%"),cb.like(root.get("requestUrl").as(String.class), "%" + apiLog.getRequestUrl() + "%"),cb.like(root.get("response").as(String.class), "%" + apiLog.getResponse() + "%")));
	            } 
				// and到一起的话所有条件就是且关系，or就是或关系
				if (predicates.size() > 0) {
					return cb.and(predicates.toArray(new Predicate[predicates.size()]));
				}
				return cb.conjunction();
			}
		};
		return apiLogRepository.findAll(querySpecifi,pageable);
	}

	public boolean exists(int id) {
		return apiLogRepository.exists(id);
	}

	public void delete(int id) {
		 apiLogRepository.delete(id);
	}
 
}
